﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

//不能又是异步又是同步，注释的是异步部分的代码

namespace IceDog.SSHConnection.LocalCommand.Components
{
    public class AsyncSSHClient : IDisposable
    {
        private readonly Process _process;

        public delegate void SSHClientEventHandler(object sender, SSHClientEventArgs e);

        public event SSHClientEventHandler OutputDataReceived;

        private string _host;
        private int _port;
        private string _username;
        private string _password;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="host">远端主机名</param>
        /// <param name="port">远端端口</param>
        /// <param name="user">登录用户名</param>
        /// <param name="password">登录密码</param>
        public AsyncSSHClient(string host, int port, string user, string password)
        {
            _host = host;
            _port = port;
            _username = user;
            _password = password;

            _process = new Process();

            ProcessStartInfo info = _process.StartInfo;
            info.CreateNoWindow = true;//不显示程序窗口
            info.UseShellExecute = false;//不使用操作系统shell启动
            info.RedirectStandardOutput = true;//重定向标准输出流
            info.RedirectStandardInput = true;//重定向标准输入流
            info.RedirectStandardError = true;//重定向标准错误流
            //info.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory

            //默认shell是 linux的

            string shellName = "/bin/bash";
            Encoding encoding = Encoding.UTF8;

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                shellName = "cmd.exe";
                encoding = Encoding.GetEncoding("GBK");
            }

            //设置三个流的编码
            info.StandardInputEncoding = encoding;
            info.StandardOutputEncoding = encoding;
            info.StandardErrorEncoding = encoding;
            //设置shell
            info.FileName = shellName;

            _process.OutputDataReceived += Process_OutputDataReceived;
            _process.ErrorDataReceived += Process_ErrorDataReceived;
            _process.Exited += Process_Exited;
            try
            {
                //启动进程
                bool startResult = _process.Start();
                if (startResult)
                {
                    //启用异步读取stdout stderr 流
                    //通过事件回调来读取结果
                    _process.BeginOutputReadLine();
                    _process.BeginErrorReadLine();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"启动 {shellName} 发生了错误，错误信息：" + ex.Message);
            }

            Execute("ssh -V");
            //if (!HasInstallSSH())
            //{
            //    throw new Exception("command ssh was not found , please install ssh");
            //}
        }

        /// <summary>
        /// 仅仅是执行命令，结果通过事件<see cref="OutputDataReceived"/> 获取
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public void Execute(string command)
        {
            _process.StandardInput.WriteLineAsync(command);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (this.OutputDataReceived == null) { return; }
            OutputDataReceived(sender, new SSHClientEventArgs("stand", e.Data));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (this.OutputDataReceived == null) { return; }
            OutputDataReceived(sender, new SSHClientEventArgs("error", e.Data));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Process_Exited(object sender, EventArgs e)
        {
            if (this.OutputDataReceived == null) { return; }
            OutputDataReceived(sender, new SSHClientEventArgs("exit", string.Empty));
        }

        public void Connecting()
        {
            Execute($"ssh -p {_port} {_username}@{_host}");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceFile">要复制的文件或文件夹，多个文件用空格分隔</param>
        /// <param name="targetDirectory">目标目录</param>
        /// <returns></returns>
        public void ScpCopyTo(string sourceFile, string targetDirectory)
        {
            Execute($"scp -P {_port} -r  {sourceFile} {_username}@{_host}:{targetDirectory}");
        }

        public void Dispose()
        {
            _process.WaitForExit();
            _process.Close();
        }
    }
}
